import re
re_docs = re.compile(r'"""(.*?)"""', re.DOTALL)

    
import py2cpp

from pygments.lexers import PythonLexer
lexer = PythonLexer(ensurenl=False)



def delete_comments(src, containing=''):
    lines = src.split('\n')
    for nr, line in enumerate(lines):
        for t in lexer.get_tokens( line ):
            #~ print(t)
            ttype, tval = t
            if str(ttype)=='Token.Comment':  # single? TODO
                if containing and containing in tval:
                    line, comment, right_empty_bla = line.rpartition(tval)
                    comment, fragment, ritht_blah = comment.partition(containing)
                    if comment.rstrip('\t #')!='':
                        line += comment
                if containing=='': # just chop whole comment
                    line, comment, right_empty_bla = line.rpartition(tval)
                        
        lines[nr] = line
    return '\n'.join(lines)
    
def replace_placeholders_to_values(src, f_args=[], f_locals={}):
    """ substitute param names with their values """
    for param in sorted(f_args):   # sorted puts params with more prepended underscores  first -- important for HIDE pattern 
        if param.startswith('_'):
            re_param = re.compile(r'\b%s\b'%param)
            #~ if param.startswith('__'):  # where extra quotes are not needed
                #~ replacement = str(f_locals[param])
            #~ else:
                #~ replacement = repr(f_locals[param])
            #~ src = re.sub(re_param, replacement, src )
            src = re.sub(re_param, str(f_locals[param]), src )
    return src

import fill_missing_code

def src_to_CLOZE(title, src, f_args=[], f_locals={}, CONVERT2CPP=False, question_text='', lang_code2img='', title_without_hints='', pygmentize=False):

    src = replace_placeholders_to_values(src, f_args, f_locals)

    #~ print(src)

    if CONVERT2CPP:
        src =  py2cpp.convert(src, GIFT=False)
        
            
    #~ print(src)
    lang = 'cpp' if CONVERT2CPP else 'py'
    
    question, answers = fill_missing_code.prepair_gaps(src, SHOWERRORS=True, lang=lang ) # questin is with gaps of format: ..<n>....

    #~ print ("Q:", question)


    if len(answers)==0:  # if no answers prepaired, no question will be given
        return ''  

    if pygmentize:
        question = code2pygmetshtml(question, lang, linenos=False, inlineCSS=True)

    for nr, (line_nr, a) in enumerate(answers):  # about SHORTANSWER https://docs.moodle.org/26/en/Embedded_Answers_%28Cloze%29_question_type#Detailed_syntax_explanations
        alternatives = ''
        if isinstance(a, (list, tuple)):
            a, alternatives = a 
            #~ alternatives = [escape_answer(alt) for alt in alternatives] -- should be escaped manulally
        if alternatives:
            alternatives += "~"   # joining symbol

        
        alternatives += ("*#atsakymui reik %s simboli" % len(a)) + ('o' if len(a)==1 else 'ų')
        
        
        a = escape_CLOZE_answer_chars(a)
        
        answer_code = "{:SHORTANSWER:=%s~%s}" % (a, alternatives) # {3<weight>:SHORTANSWER:=Berlin#comment~another answer}
        question = question.replace('..%s....'%nr, answer_code) 

    return """
    <!-- question: ...nr...  -->
    <question type="cloze">
    <name> <text>%s</text>  </name>
    <questiontext format="html">
    <text><![CDATA[Įrašykite, ko trūksta <span style="color:grey">(naudodami minimaliai simbolių/tarpų)</span>
    <br/> <pre>%s</pre>
    Kad būtų atspausdinta: <pre>""" % ( title,  question )

    # pabaigoj
CLOZE_TPL_END =  """</pre>]]></text>
    </questiontext>
    <generalfeedback>
    <text></text>
    </generalfeedback>
    <shuffleanswers>0</shuffleanswers>
    </question>
    """


def src_to_GIFT(title, src, f_args=[], f_locals={}, CONVERT2CPP=False, question_text='', lang_code2img='', title_without_hints='', markup_type='markdown'):

    src = replace_placeholders_to_values(src, f_args, f_locals)
    src = delete_comments(src, containing='HIDE')
    
    # for negatives numbers: tidy minuses -- simplify signs or put brackets 
    src = src.replace('+-', '-').replace('+ -', '-').replace('--', '+').replace('- -', '+') # better use regexp or AST... (someday :P)
    re_minus_unbraced = re.compile(r'([*/] *?)(-\d+(\.\d+)?)')
    src = re_minus_unbraced.sub(r'\1(\2)', src)
            

    docs_match = re_docs.search(src)  # get question text from """docs"""
    if docs_match:
        question_text += docs_match.group(1)
        #~ src = src.replace(docs_match.group(0), docs+'\n')
        src = src.replace(docs_match.group(0), '' )
        
    #~ src = '\n'.join( src.split('\n')[1:] )  # get rid of first definition line

    if CONVERT2CPP:
        src =  py2cpp.convert(src)
        
    if lang_code2img:
        name = title_without_hints or  title
        code_highlight(name, lang_code2img, src, LINENOS4IMG=True)
        src = img_placer('markdown', lang_code2img+'_'+name)
    else:
        src = escape_GIFT_spec_chars(src)

    question_text = escape_GIFT_spec_chars(question_text)
    src = question_text+'\n\n'+ src
    src = src.replace('\n', '\n\\n')  # GIFT format needs explicit \n
    title = escape_GIFT_spec_chars(title)
    
    return "::%s::[%s]\n\\n%s" %( title, markup_type, src )  # question title, format, and text


def escape_CLOZE_answer_chars(txt):
    # https://docs.moodle.org/22/en/Embedded_Answers_%28Cloze%29_question_type#Importing_CLOZE_questions
    for char in '*#}':   # \ ?
        txt = txt.replace(char, '\\'+char)
    if '~' in txt and txt.index('~') > 0:
        print( "WARNING, tilde (~)  better not be in answer, except first position")
        txt = txt[0]+txt[1:].replace('~', '\\~')
    if txt.endswith('\\'):
        txt = txt+' ' #at least in older Moodle versions 2.6 without extra space - it would apply to answer separator (~) char
    return txt


def escape_GIFT_spec_chars(txt, html_escape=False):
    for char in '=~#{}:':   # what about = symbol?
        txt = txt.replace(char, '\\'+char)
        # Quotation signs: " can lead to trouble anyhow in both places. Use the HTML entity: &quot;

    if html_escape:
        html_escapes = {'<': 'lt', '>':'gt', '#':'#35'} # not to interfere with markdown 
        for char, escape in html_escapes.items():
            txt = txt.replace(char, '&'+escape+';')
        
    return txt

###################################
########   code 2 img     #########
###################################

path2img='output/code2img/html2img/'
imgwebdir = 'http://galvosukykla.lt/moodle_code_quiz.img/'


def escape_path(txt):
    lit = 'ąčęėįšųūžĄČĘĖĮŠŲŪŽ'
    lat = 'aceeisuuzACEEISUUZ'
    for a, b in zip(lit, lat):
        txt = txt.replace(a, b) 
    txt = txt.replace('/', '_') \
              .replace(' ', '_') \
              .replace('\\', '_') \
              .replace(':', '_') \
              .replace('#', ' ') \
              .replace('?', '.') \
              .replace('!', '.') \
              .replace('"', '_') \
              .replace('\'', '_') \
              .replace('‘', '`') \
              .replace('’', '`') \
              #~ .replace('', '') \
    return txt 

def urlescape(txt):
    return txt.replace(' ', '%20')


def code2pygmetshtml(code, lang, linenos=False, inlineCSS=False):
    # generate highlighted code html (to convert to img)
    from pygments import highlight
    if lang == 'py':
        from pygments.lexers import PythonLexer as Lexer
    if lang == 'cpp':
        from pygments.lexers import CppLexer as Lexer
    
    from pygments.formatters import HtmlFormatter
    #~ formatter = HtmlFormatter()
    formatter = HtmlFormatter(linenos=linenos, noclasses=inlineCSS)
    #~ formatter = HtmlFormatter(linenos=True, cssclass="source")
    html = highlight(code, Lexer(), formatter)
    return html


def code_highlight(name, lang, code, linenos=False):

    from pygments.formatters import HtmlFormatter

    html = code2pygmetshtml(code, lang, linenos)

    if conv2IMG:
        if not os.path.exists(path2img+'pygments_style.css'):
            with open(path2img+'pygments_style.css', 'w') as f:
                f.write( HtmlFormatter().get_style_defs('.highlight') )
        
        with open(path2img+lang+'_'+escape_path(name)+'.html', 'w') as f:
            f.write( """
            <!doctype html>
            <head>
            <meta charset="utf-8">
            <link rel="stylesheet" href="pygments_style.css">
            </head>
            <body>
            """ + html + "</body>")


def img_placer(textformat, img_name ):
    if textformat == 'html':
        return '<img src="'+imgwebdir+urlescape(escape_path(img_name))+'.html.png" />'

    if textformat == 'markdown':
        return  '![alt '+img_name+']('+imgwebdir+urlescape(escape_path(img_name))+'.html.png )'
